﻿/*-------------------------------------------------------------------------
* 命名空间: WaferSelectV3.Common/SingleInstanceManager
* 类       名: SingleInstanceManager
* 功      能:  TD
* 时      间:  2024-04-18 17:51:29
* 版      本:  V1.0
* 作      者:  Fioman
* 格      言:  Talk is cheap,show me the code ^_^
*-------------------------------------------------------------------------*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace YiDunXray.Common
{
    public class SingleInstanceManager
    {
        /// <summary>
        /// 互斥体Id,用于创建互斥体的标识符,相同标识符表示相同的互斥体
        /// </summary>
        private const string _mutexId = "MutexId-Fioman-2024-04-18-YiDunXray";
        /// <summary>
        /// 事件句柄创建的时候的时间Id,相同Id代表相同事件
        /// </summary>
        private const string _eventHandleId = "EventId-Fioman-2024-04-18-YiDunXray";
        /// <summary>
        /// 互斥体
        /// </summary>
        private static Mutex? _mutex;
        /// <summary>
        /// 事件句柄
        /// </summary>
        private static EventWaitHandle? _eventWaitHandle;

        /// <summary>
        /// 检测应用是否已经启动
        /// </summary>
        public static void SingleInstanceCheck()
        {
            /*
             * 创建互斥体,互斥体构造方法,各个参数的含义:
             * 1) true,表示是否马上拥有这个互斥体资源,如果这个互斥体资源已经存在了,就会使用旧的,CreateNew就返回了false.
             * 2) _mutexId: 互斥体的Id,用来唯一标识一个互斥体,如果Id相同,那么就是同一个互斥体,创建的时候就不会创建新的,
             *                       createdNew就返回了false.
             *  3) createNew, 是否重新创建了一个互斥体,如果返回true,表示重新创建了一个互斥体,如果为false,表示这个互斥体已经存在
             *       就不再重新创建,就返回已经存在的互斥体
             */
            _mutex = new Mutex(true, _mutexId, out bool createdNew);
            if (!createdNew)
            {
                // 互斥体已经存在,证明程序已经在运行,这个时候,就去创建EventWaitHanle事件句柄
                // false,表示创建的这个事件句柄一开始是没有信号的, AutoReset表示会自动清空信号
                _eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset, _eventHandleId);
                // 发送信号,给之前的进程发送信号
                _eventWaitHandle.Set();
                // 关闭当前的应用
                Environment.Exit(0);
            }
        }


        // 监听程序启动事件,在window加载的时候调用(你想要在哪里激活,就在哪里调用,一般在主窗口那里激活,所以说在
        // 主窗口那里调用.)
        public static void AppStartEventListen(Action? showWindow)
        {
            /*
             * 这里为什么要重新开启一个任务,如果不重新开启会有什么后果呢?
             * 因为这个函数是UI线程进行调用的,所以它会在UI线程上进行执行,在UI线程上进行执行的时候,
             * while(true) 后面的waitone会阻塞UI线程,所以这里要创建一个新的任务,避免UI线程阻塞
             */
            Task.Run(() =>
            {
                while (true)
                {
                    _eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset, _eventHandleId);
                    _eventWaitHandle.WaitOne();
                    showWindow?.Invoke();
                }
            });
        }

    }
}
